package com.adam.management.config;

import com.adam.management.component.MyAuthenticationAccessDeniedHandler;
import com.adam.management.component.MySessionExpiredStrategy;
import com.adam.management.controller.UserLoginAuthenticationFailureHandler;
import com.adam.management.controller.UserLoginAuthenticationSuccessHandler;
import com.adam.management.filter.ValidateCodeFilter;
import com.adam.management.service.impl.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @projectName: adam-management-system
 * @description:
 * @author: Adam
 * @create: 2019-11-26 19:09
 **/

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { // 父类中有默认的安全配置，需要我们用子类中的自定义配置覆盖

    @Autowired
    private UserDetailServiceImpl userDetailService;
    @Autowired
    private UserLoginAuthenticationSuccessHandler userLoginAuthenticationSuccessHandler;

    @Autowired
    private UserLoginAuthenticationFailureHandler userLoginAuthenticationFailureHandler;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private ValidateCodeFilter validateCodeFilter;

    @Autowired
    private MySessionExpiredStrategy sessionExpiredStrategy;

    @Autowired private MyAuthenticationAccessDeniedHandler authenticationAccessDeniedHandler;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器
                    .authorizeRequests() // 授权配置
                    .antMatchers("/static/**","/login","/login/**").permitAll()
                    .antMatchers("/register","register/**").permitAll()
                    .antMatchers("/code/image").permitAll()
                    .antMatchers("/session/invalid").permitAll()
                    .anyRequest().authenticated() // 剩下的资源需要认证
                .and()
                    .formLogin().loginPage("/login/page")
                    .loginProcessingUrl("/login")
                    .successHandler(userLoginAuthenticationSuccessHandler)
                    .failureHandler(userLoginAuthenticationFailureHandler)
                .and()
                    .rememberMe()
                    .tokenRepository(persistentTokenRepository()) // 配置 token 持久化仓库
                    .tokenValiditySeconds(3600) // remember 过期时间，单为秒
                    .userDetailsService(userDetailService) // 处理自动登录逻辑
                .and()
                    .sessionManagement() // 添加 Session管理器
                    .invalidSessionUrl("/session/invalid") // Session失效后跳转到这个链接
                    .maximumSessions(1) //session的最大并发数为1个
                    .expiredSessionStrategy(sessionExpiredStrategy)
                    .and()
                .and()
                    .logout()
                    .logoutUrl("/signout")
                    .logoutSuccessUrl("/signout/success")
                    .deleteCookies("JSESSIONID")
                .and()
                    .exceptionHandling()
                    .accessDeniedHandler(authenticationAccessDeniedHandler)
                .and()
                .csrf().disable() // 暂时禁用csrf 保护
                .headers().frameOptions().sameOrigin(); //X-Frame-Options属性设置为SAMEORIGIN 运行iframe访问

    }


    //这里配置PasswordEncoder,BCryptPasswordEncoder是security提供的PasswordEncorder的一个实现类
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }


    /**
      * oken持久化对象
      * @author lijie
      * @param
      * @return
      * @time 14:29
      */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        jdbcTokenRepository.setCreateTableOnStartup(false);
        return jdbcTokenRepository;
    }

}
